using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using elibrary.Classes;
using elibrary.Models;
using elibrary.Models.Entities;
using BookStatus = elibrary.Models.Entities.Book.BookStatus;
using BookType = elibrary.Models.Entities.Book.BookType;
using BookQuality = elibrary.Models.Entities.Book.BookQuality;

namespace elibrary.Models.Managers
{
	public class BookManager
	{
		private DataContext ctx;
		private DbSet<Book> books;

		public BookManager(DataContext ctx)
		{
			this.ctx = ctx;
			this.books = ctx.books;
		}

		public void add(Book book,bool autoSave=true)
		{
			books.Add(book);
			
			if (autoSave)
				ctx.SaveChanges();
		}

		public List<Dictionary<string,object>> getMarketplaceBooks()
		{
			List<Dictionary<string,object>> toReturn = new List<Dictionary<string,object>>();
			List<Book> availabe = this.getAllAvailable();

			foreach(var book in availabe)
				toReturn.Add(book.marketplaceObject;

			return toReturn;
		}

		public Book get(int id)
		{
			return books.SingleOrDefault(q => q.id == id);
		}

		public List<Book> getSoldSecondhandBooks(int uid = -1)
		{
			List<Book> sold = getAllByType(BookType.Secondhand);
			sold = Utilities.ensureRs<Book>(sold.Where(q => q.status == BookStatus.sold));

			return uid == -1 ? sold : Utilities.ensureRs<Book>(sold.Where(
				q => q.uploaderId == uid));
		}

		public List<Book> getAll(int uid = -1, bool includeDeleted = false)
		{
			List<Book> toReturn = Utilities.ensureRs<Book>(books);

			if (uid != -1)
				toReturn = Utilities.ensureRs<Book>(toReturn.Where(q => q.uploaderId == uid));

			if (!includeDeleted)
				toReturn = Utilities.ensureRs<Book>(toReturn.Where(
					q => q.status != BookStatus.Deleted));

			return toReturn;
		}

		public List<Book> getAllAvailable(int uid = -1)
		{
			var r = books.Where(q => q.status == BookStatus.Available);

			if (uid != -1 && r != null && r.Any())
				r = r.Where(q => q.uploaderId == uid);

			return Utilities.ensureRs<Book>(r);
		}

		public List<Book> getAvailableNewBooks()
		{
			return Utilities.ensureRs<Book>(books.Where(q => q.status == BookStatus.Available && 
				q.type == BookType.Firsthand));
		}

		public List<Book> getAvailableSecondhandBooks()
		{
			return Utilities.ensureRs<Book>(books.Where(q => q.status == BookStatus.Available &&
				q.type == BookType.Secondhand));
		}

		public List<Book> getAllByStatus(BookStatus status)
		{
			var r = books.Where(q => q.status == status);

			return Utilities.ensureRs<Book>(r);
		}

		public List<Book> getAllByType(BookType type, bool includeDeleted = false)
		{
			var r = includeDeleted ? books.Where(q => q.type == type) :
				books.Where(q => q.type == type && q.status != BookStatus.Deleted);

			return Utilities.ensureRs<Book>(r);
		}

		public List<Book> getInReviewingBooks(int uid = -1)
		{
			List<Book> inReview = getAllByStatus(BookStatus.InReview);

			return uid == -1 ? inReview : Utilities.ensureRs<Book>(inReview.Where(
				q => q.uploaderId == uid));
		}

		public List<Book> getDeletedBooks(int uid = -1)
		{
			List<Book> deleted = getAllByStatus(BookStatus.Deleted);

			return uid == -1 ? deleted : Utilities.ensureRs<Book>(deleted.Where(
				q => q.uploaderId == uid));
		}

		public List<Book> getAllByUser(int uid, bool includeDeleted = false)
		{
			var r = includeDeleted ? books.Where(q => q.uploaderId == uid) :
				books.Where(q => q.uploaderId == uid && q.status != BookStatus.Deleted);

			return Utilities.ensureRs<Book>(r);
		}

		public List<Book> getAllByCategory(string cname, int cid=-1, bool includeDeleted = false)
		{
			BookCategoryManager bcManager = new BookCategoryManager(ctx);
			List<BookCategory> bcs = bcManager.getAllByCategory(cname,cid);
			List<Book> toReturn = new List<Book>();

			foreach(var item in bcs)
			{
				if (!includeDeleted && item.book.status == BookStatus.Deleted)
					continue;

				toReturn.Add(item.book);
			}

			return toReturn;
		}

		public void delete(int id,bool autoSave=true)
		{
			delete(get(id),autoSave);
		}

		public void delete(Book book,bool autoSave=true)
		{
			if (book == null)
				return;

			books.Remove(book);
			if (autoSave)
				ctx.SaveChanges();
		}
	}
}